package cn.wolfcode.wolf2w.business.service.impl;

import cn.wolfcode.wolf2w.business.api.RemoteDestinationService;
import cn.wolfcode.wolf2w.business.api.domain.*;
import cn.wolfcode.wolf2w.business.mapper.*;
import cn.wolfcode.wolf2w.business.query.StrategyQuery;
import cn.wolfcode.wolf2w.business.service.IStrategyService;
import cn.wolfcode.wolf2w.business.util.DateUtil;
import cn.wolfcode.wolf2w.business.vo.ThemeVO;
import cn.wolfcode.wolf2w.common.core.constant.SecurityConstants;
import cn.wolfcode.wolf2w.common.core.context.SecurityContextHolder;
import cn.wolfcode.wolf2w.common.core.domain.R;
import cn.wolfcode.wolf2w.common.redis.service.RedisService;
import cn.wolfcode.wolf2w.common.redis.util.RedisKeys;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 攻略Service业务层处理
 *
 * @author dh
 * @date 2025-09-16
 */
@Service
@Transactional
public class StrategyServiceImpl extends ServiceImpl<StrategyMapper,Strategy> implements IStrategyService {



    @Resource
    private StrategyRankMapper rankMapper;

    @Resource
    private StrategyThemeMapper themeMapper;

    @Resource
    private StrategyCatalogMapper catalogMapper;

    @Resource
    private RemoteDestinationService remoteDestinationService;

    @Resource
    private StrategyContentMapper contentMapper;

    @Resource
    private StrategyConditionMapper conditionMapper;

    @Autowired
    private RedisService redisService;

    @Override
    public IPage<Strategy> queryPage(String orderBy, StrategyQuery qo, Long refid, Long type) {
        IPage<Strategy> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());
        if (refid == null){
            return lambdaQuery()
                    .page(page);
        }
        if (type == 3){
            return lambdaQuery().eq(Strategy::getThemeId, refid)
                    .orderByDesc(Strategy::getViewnum)
                    .page(page);
        }else {
            return lambdaQuery().eq(Strategy::getDestId,refid)
                    .orderByDesc(Strategy::getViewnum)
                    .page(page);
        }
    }

    @Override
    public IPage<Strategy> queryPage(StrategyQuery qo) {
        IPage<Strategy> page = new Page<>(qo.getCurrentPage(), qo.getPageSize());
        return lambdaQuery()
                .page(page);
    }

    @Override
    public List<Strategy> queryViewTop3(Long destId) {
        List<Strategy> list = lambdaQuery()
                .eq(Strategy::getDestId, destId)
                .orderByDesc(Strategy::getViewnum)
                .last("limit 3")
                .list();
        return list;
    }

    @Override
    public void statisRank() {
        // 国外数据
        List<Strategy> abroadList = lambdaQuery().eq(Strategy::getIsabroad, 1)
                .orderByDesc(Strategy::getViewnum)
                .last("limit 10")
                .list();
        // 国内数据
        List<Strategy> ChinaList = lambdaQuery().eq(Strategy::getIsabroad, 0)
                .orderByDesc(Strategy::getViewnum)
                .last("limit 10")
                .list();
        // 全球数据
        List<Strategy> hotList = lambdaQuery()
                .orderByDesc(Strategy::getViewnum)
                .last("limit 10")
                .list();

        Date now = new Date();

        addRank(abroadList,now,1);
        addRank(ChinaList,now,2);
        addRank(hotList,now,3);
    }

    @Override
    public List<ThemeVO> queryTheme() {
        QueryWrapper<Strategy> wrapper = new QueryWrapper<>();
        wrapper.groupBy("theme_name");
        wrapper.select("theme_name, GROUP_CONCAT(DISTINCT dest_id) ids" +
                ", GROUP_CONCAT(DISTINCT dest_name) names");
        List<Map<String, Object>> list = baseMapper.selectMaps(wrapper);
        ArrayList<ThemeVO> themeVOArrayList = new ArrayList<>();
        for (Map<String, Object> map : list) {
            String theme_name = (String) map.get("theme_name");
            String ids = (String) map.get("ids");
            String[] idArr = ids.split(",");
            String names = (String) map.get("names");
            String[] nameArr = names.split(",");
            List<Destination> destinations = new ArrayList<>();
            for (int i = 0; i < idArr.length; i++) {
                Long id = Long.valueOf(idArr[i]);
                String name = nameArr[i];
                Destination destination = new Destination();
                destination.setId(id);
                destination.setName(name);
                destinations.add(destination);
            }
            ThemeVO themeVO = new ThemeVO(theme_name, destinations);
            themeVOArrayList.add(themeVO);
        }
        return themeVOArrayList;
    }

    @Override
    public void addStrategy(Strategy strategy) {
        StrategyTheme theme = themeMapper.selectById(strategy.getThemeId());
        strategy.setThemeName(theme.getName());

        StrategyCatalog catalog = catalogMapper.selectById(strategy.getCatalogId());
        strategy.setCatalogName(catalog.getName());
        strategy.setDestId(catalog.getDestId());
        strategy.setDestName(catalog.getDestName());
        strategy.setCreateTime(new Date());
        strategy.setViewnum(0l);
        strategy.setReplynum(0l);
        strategy.setFavornum(0l);
        strategy.setSharenum(0l);
        strategy.setThumbsupnum(0l);
        Boolean b = remoteDestinationService.isAbroad(strategy.getDestId(), SecurityConstants.INNER).getData();
        strategy.setIsabroad(b?1l:0l);
        baseMapper.insert(strategy);
        Long strategyId = strategy.getId();
        strategy.getContent().setId(strategyId);
        contentMapper.insert(strategy.getContent());


    }

    @Override
    public void statisCondition() {
        /**
         * #type=1 查国外
         * SELECT dest_id refid, dest_name name, COUNT(1) count
         * from ta_strategy
         * WHERE isabroad = 1
         * GROUP BY dest_id, dest_name
         * ORDER BY count desc
         */
//        查国外
        QueryWrapper<Strategy> wrapper = new QueryWrapper<>();
        wrapper.eq("isabroad",1);
        wrapper.groupBy("dest_id, dest_name");
        wrapper.select("dest_id refid, dest_name name, COUNT(1) count");
        wrapper.orderByDesc("count");
        List<Map<String, Object>> abroadList = baseMapper.selectMaps(wrapper);

        // 国内
        wrapper.clear();
        wrapper.eq("isabroad",0);
        wrapper.groupBy("dest_id, dest_name");
        wrapper.select("dest_id refid, dest_name name, COUNT(1) count");
        wrapper.orderByDesc("count");
        List<Map<String, Object>> chinaList = baseMapper.selectMaps(wrapper);

        /**
         * #type=3 查主题
         * SELECT theme_id refid, theme_name name, count(1) count
         * from ta_strategy
         * GROUP BY theme_id, theme_name
         * order by count desc
         */
        // 主题
        wrapper.clear();
        wrapper.groupBy("theme_id, theme_name");
        wrapper.select("theme_id refid, theme_name name, count(1) count");
        wrapper.orderByDesc("count");
        List<Map<String, Object>> themeList = baseMapper.selectMaps(wrapper);

        Date date = new Date();

        addCondition(abroadList,date,1l);
        addCondition(chinaList,date,2l);
        addCondition(themeList,date,3l);
    }

    @Override
    public Map<String, Object> viewnumIncr(Long sid) {
        String key = getKey(sid);
        redisService.incrementCacheMapValue(key,"viewnum",1);
        Map<String, Object> cacheMap = redisService.getCacheMap(key);
        return cacheMap;
    }

    @Override
    public Map<String, Object> replynumIncr(Long sid) {
        String key = getKey(sid);
        redisService.incrementCacheMapValue(key,"replynum",1);
        Map<String, Object> cacheMap = redisService.getCacheMap(key);
        return cacheMap;
    }

    @Override
    public Map<String, Object> favor(Long sid) {
        Long userId = SecurityContextHolder.getUserId();
        String key = RedisKeys.USER_STRATEGY_FAVOR.join(String.valueOf(userId));
        //如果用户没有收藏并且没有该用户对应的key,创建用户对应的sid存入到sids
        if (! redisService.hasKey(key)){
            Set<Long> sids = new HashSet<>();
            //redis删除set不保留set空集合结构,存一个-1l防止set为空
            sids.add(-1l);
            redisService.setCacheSet(key,sids);
        }
        boolean b = false;
        String hashkey = RedisKeys.STRATEGY_STATIS_HASH.join(String.valueOf(sid));
        if (redisService.isCacheSetContains(key,sid)){
            //取消收藏
            redisService.deleteCacheSetValue(key,sid);
            redisService.incrementCacheMapValue(hashkey,"favornum",-1);
        }else {
            //添加收藏
            redisService.addCacheSetValue(key,sid);
            redisService.incrementCacheMapValue(hashkey,"favornum",1);
            b = true;
        }
        Map<String, Object> cacheMap = redisService.getCacheMap(hashkey);
        cacheMap.put("result",b);
        return cacheMap;

    }

    @Override
    public Boolean isUserFavor(Long uid, Long sid) {
        String key = RedisKeys.USER_STRATEGY_FAVOR.join(String.valueOf(uid));
        //如果用户没有收藏并且没有该用户对应的key,创建用户对应的sid存入到sids
        if (! redisService.hasKey(key)){
            Set<Long> sids = new HashSet<>();
            //redis删除set不保留set空集合结构,存一个-1l防止set为空
            sids.add(-1l);
            redisService.setCacheSet(key,sids);
        }
        return redisService.isCacheSetContains(key,sid);
    }

    @Override
    public void strategyStatisHashPersistence() {
        String hashkey = RedisKeys.STRATEGY_STATIS_HASH.join("*");
        //所有统计数字的key的数字
        Collection<String> keys = redisService.keys(hashkey);
        if (! keys.isEmpty() && keys.size() > 0){
            for (String key : keys) {
                Map<String, Object> cacheMap = redisService.getCacheMap(key);
                lambdaUpdate().eq(Strategy::getId,cacheMap.get("id"))
                        .set(Strategy::getViewnum,cacheMap.get("viewnum"))
                        .set(Strategy::getReplynum,cacheMap.get("replynum"))
                        .set(Strategy::getFavornum,cacheMap.get("favornum"))
                        .set(Strategy::getSharenum,cacheMap.get("sharenum"))
                        .set(Strategy::getThumbsupnum,cacheMap.get("thumbsupnum"))
                        .update();
            }
        }

    }

    @Override
    public Map<String, Object> thumbsup(Long sid) {
        //注入uid
        Long userId = SecurityContextHolder.getUserId();
        //拼key
        String key = RedisKeys.USER_STRATEGY_THUMBSUP.join(sid.toString(), userId.toString());
        //计算过期时间
        Date begin = new Date();
        Date end = DateUtil.getEndDate(begin);
        long ttl = DateUtil.getDateBetween(begin, end);

        if (! redisService.hasKey(key)){
            redisService.setCacheObject(key,0,ttl, TimeUnit.SECONDS);
        }
        //点赞次数++做判断
        Long count = redisService.incrementCacheObjectValue(key, 1);
        String hashkey = RedisKeys.STRATEGY_STATIS_HASH.join(sid.toString());
        Boolean result = false;
        //判断点赞次数,返回合适的result
        if (count <= 3){
            result = true;
            //真实的点赞次数加1
            redisService.incrementCacheMapValue(hashkey,"thumbsupnum",1);
        }
        //将result添加到map中
        Map<String, Object> cacheMap = redisService.getCacheMap(hashkey);
        cacheMap.put("result",result);
        //返回map
        return cacheMap;
    }

    private String getKey(Long sid) {
        String key = RedisKeys.STRATEGY_STATIS_HASH.join(sid.toString());
        if ( ! redisService.hasKey(key)){
            Strategy strategy = this.getById(sid);
            HashMap<String, Object> map = new HashMap<>();
            map.put("viewnum", Integer.valueOf(strategy.getViewnum().toString()));
            map.put("replynum", Integer.valueOf(strategy.getReplynum().toString()));
            map.put("sharenum", Integer.valueOf(strategy.getSharenum().toString()));
            map.put("favornum", Integer.valueOf(strategy.getFavornum().toString()));
            map.put("thumbsupnum", Integer.valueOf(strategy.getThumbsupnum().toString()));
            map.put("id",Integer.valueOf(strategy.getId().toString()));
            redisService.setCacheMap(key,map);
        }
        return key;
    }

    private void addCondition(List<Map<String, Object>> list,Date date,Long type){
        for (Map<String, Object> map : list) {
            Long refid = Long.valueOf(map.get("refid").toString());
            String name = map.get("name").toString();
            Long count = Long.valueOf(map.get("count").toString());
            StrategyCondition condition = new StrategyCondition();
            condition.setRefid(refid);
            condition.setName(name);
            condition.setCount(count);
            condition.setStatisTime(date);
            condition.setType(type);
            conditionMapper.insert(condition);
        }
    }

    private  void addRank(List<Strategy> list,Date now,long type){
        for (Strategy strategy : list) {
            StrategyRank rank = new StrategyRank();
            rank.setStrategyId(strategy.getId());
            rank.setStrategyTitle(strategy.getTitle());
            rank.setDestId(strategy.getDestId());
            rank.setDestName(strategy.getDestName());
            rank.setStatisnum(strategy.getViewnum());
            rank.setStatisTime(now);
            rank.setType(type);
            rankMapper.insert(rank);
        }
    }
}
